package lin

import (
	"encoding/json"
	"errors"
	"sort"
	"sync"
	"time"
)

type J键值表 struct {
	原始数据 map[string]any
	读写许可 *sync.RWMutex
}

func NewJ键值表(是否_线程安全 ...bool) (返回_键值表 J键值表) {
    var 锁 *sync.RWMutex
    if len(是否_线程安全) > 0 && 是否_线程安全[0] {
        锁 = &sync.RWMutex{}
    }
    return J键值表{
        原始数据: make(map[string]any),
        读写许可: 锁,
    }
}

func NewJ键值表_直接赋值(是否_线程安全 bool, 键值 ...any) (返回_键值表 J键值表, 返回错误 error) {
    var 锁 *sync.RWMutex
    if 是否_线程安全 {
        锁 = &sync.RWMutex{}
    }
    表 := J键值表{
        原始数据: make(map[string]any),
        读写许可: 锁,
    }
    err := 表.L连续赋值(键值...)
    return 表, err
}

func (类 *J键值表) 初始化() {
	if 类.原始数据 == nil {
		类.原始数据 = make(map[string]any)
	}
}

func (类 *J键值表) ZX置线程安全() {
    if 类.读写许可 == nil {
        类.读写许可 = &sync.RWMutex{}
    }
}

// @ 支持 json(字节集的json) && map[string]any && J键值表 && 可以json化的map
func (类 *J键值表) ZR载入(载入值 any) (返回_错误 error) {
	if 类.读写许可 != nil {
		类.读写许可.Lock()
		defer 类.读写许可.Unlock()
	}

	类.原始数据 = make(map[string]any)
	switch 当前值 := 载入值.(type) {
	case string:
		返回_错误 = json.Unmarshal([]byte(当前值), &类.原始数据)
		return
	case []byte:
		返回_错误 = json.Unmarshal(当前值, &类.原始数据)
		return
	case map[string]any:
		返回_错误 = 键值列表_类型筛选(当前值)
		if 返回_错误 != nil {
			return
		}
		新值, err := 键值列表_深拷贝(当前值)
		类.原始数据, _ = 新值.(map[string]any)
		返回_错误 = err
		return
	case J键值表:
		if &类.原始数据 == &当前值.原始数据 {
			返回_错误 = errors.New("错误:自己不能载入自己")
			return
		}
		类.原始数据 = 当前值.D到map()
		return
	default:
		JSON, err := json.Marshal(载入值)
		if err != nil {
			返回_错误 = err
			return
		}
		返回_错误 = json.Unmarshal([]byte(JSON), &类.原始数据)
		return
	}

}

func (类 *J键值表) D到map() (返回_值 map[string]any) {
	类.初始化()
	if 类.读写许可 != nil {
		类.读写许可.RLock()
		defer 类.读写许可.RUnlock()
	}
	新值, _ := 键值列表_深拷贝(类.原始数据)
	返回_值, _ = 新值.(map[string]any)
	return
}

func (类 *J键值表) Q清空() bool {
	if 类.读写许可 != nil {
		类.读写许可.Lock()
		defer 类.读写许可.Unlock()
	}
	类.原始数据 = make(map[string]any)
	return true
}
func (类 *J键值表) D到JSON() (返回_值 string) {
	类.初始化()
	if 类.读写许可 != nil {
		类.读写许可.RLock()
		defer 类.读写许可.RUnlock()
	}

	新值, _ := 键值列表_深拷贝(类.原始数据)
	转换数据 := 键值列表_JSON之前处理(新值)
	JSON, err := json.Marshal(转换数据)
	if err != nil {
		返回_值 = "{}"
		return
	}
	返回_值 = string(JSON)
	return
}
func (类 *J键值表) D到新键值表() (返回_值 J键值表) {
	返回_值.Q清空()
	类.初始化()
	if 类.读写许可 != nil {
		if &类.读写许可 == &返回_值.读写许可 {
			return
		}
		类.读写许可.RLock()
		defer 类.读写许可.RUnlock()
	}
	返回_值.ZR载入(类.原始数据)
	return
}

// 路径  用 . 分割  自动去除 前后包裹的 []  如 路径1.路径2.[0].路径4 | 路径1.路径2.0.路径4|路径1.[路径2].0.路径4"
// 索引 如果 后面索引不为空 则走 路径+索引 混合
func (类 *J键值表) Q取值(路径或索引 any, 索引 ...any) (返回_值 any, 返回_错误 error) {
	路径组, err := 值列路径(路径或索引, 索引...)
	if err != nil {
		返回_错误 = err
		return
	}

	类.初始化()
	if 类.读写许可 != nil {
		类.读写许可.RLock()
		defer 类.读写许可.RUnlock()
	}

	返回_值, 返回_错误 = 键值列表_取值(类.原始数据, 路径组)
	return
}

// 路径  用 . 分割  自动去除 前后包裹的 []  如 路径1.路径2.[0].路径4 | 路径1.路径2.0.路径4|路径1.[路径2].0.路径4"
// 索引 如果 后面索引不为空 则走 路径+索引 混合
func (类 *J键值表) QW取文本(路径或索引 any, 索引 ...any) (返回_值 string) {
	值, 返回_错误 := 类.Q取值(路径或索引, 索引...)
	if 返回_错误 != nil {
		return
	}
	返回_值 = any_到文本(值)
	return
}

// 路径  用 . 分割  自动去除 前后包裹的 []  如 路径1.路径2.[0].路径4 | 路径1.路径2.0.路径4|路径1.[路径2].0.路径4"
// 索引 如果 后面索引不为空 则走 路径+索引 混合
func (类 *J键值表) QZ取整数(路径或索引 any, 索引 ...any) (返回_值 int) {
	值, _ := 类.Q取值(路径或索引, 索引...)
	返回_值 = 全_类型.D到整数(值)
	return
}

// 路径  用 . 分割  自动去除 前后包裹的 []  如 路径1.路径2.[0].路径4 | 路径1.路径2.0.路径4|路径1.[路径2].0.路径4"
// 索引 如果 后面索引不为空 则走 路径+索引 混合
func (类 *J键值表) QX取小数(路径或索引 any, 索引 ...any) (返回_值 float64) {
	值, _ := 类.Q取值(路径或索引, 索引...)
	返回_值 = 全_类型.D到双精度小数(值)
	return
}

// 路径  用 . 分割  自动去除 前后包裹的 []  如 路径1.路径2.[0].路径4 | 路径1.路径2.0.路径4|路径1.[路径2].0.路径4"
// 索引 如果 后面索引不为空 则走 路径+索引 混合
func (类 *J键值表) QL取逻辑值(路径或索引 any, 索引 ...any) (返回_值 bool) {
	值, _ := 类.Q取值(路径或索引, 索引...)
	返回_值 = 全_类型.D到逻辑值(值)
	return
}

// 路径  用 . 分割  自动去除 前后包裹的 []  如 路径1.路径2.[0].路径4 | 路径1.路径2.0.路径4|路径1.[路径2].0.路径4"
// 索引 如果 J键值表 则走 路径+索引 混合
func (类 *J键值表) QM取map(路径或索引 any, 索引 ...any) (返回_值 map[string]any) {
	值, _ := 类.Q取值(路径或索引, 索引...)
	返回_值, _ = 值.(map[string]any)
	return

}

// 路径  用 . 分割  自动去除 前后包裹的 []  如 路径1.路径2.[0].路径4 | 路径1.路径2.0.路径4|路径1.[路径2].0.路径4"
// 索引 如果 后面索引不为空 则走 路径+索引 混合
func (类 *J键值表) QJ取键值表(路径或索引 any, 索引 ...any) (返回_值 J键值表) {
	返回_值.Q清空()
	值, 返回_错误 := 类.Q取值(路径或索引, 索引...)
	if 返回_错误 != nil {
		return
	}
	// 新值, OK := 值.(map[string]any)
	// if !OK {
	// 	return
	// }
	返回_值.ZR载入(值)
	return
}

// 路径  用 . 分割  自动去除 前后包裹的 []  如 路径1.路径2.[0].路径4 | 路径1.路径2.0.路径4|路径1.[路径2].0.路径4"
// 索引 如果 后面索引不为空 则走 路径+索引 混合
func (类 *J键值表) QQ取切片(路径或索引 any, 索引 ...any) (返回_值 []any) {
	值, _ := 类.Q取值(路径或索引, 索引...)
	返回_值, _ = 值.([]any)
	return
}

// 路径  用 . 分割  自动去除 前后包裹的 []  如 路径1.路径2.[0].路径4 | 路径1.路径2.0.路径4|路径1.[路径2].0.路径4"
// 索引 如果 后面索引不为空 则走 路径+索引 混合
func (类 *J键值表) QL取列表(路径或索引 any, 索引 ...any) (返回_值 L列表) {
	返回_值.Q清空()
	值, 返回_错误 := 类.Q取值(路径或索引, 索引...)
	if 返回_错误 != nil {
		return
	}
	返回_值.ZR载入(值)
	return
	// switch 当前值 := 值.(type) {
	// case []any:
	// 	返回_值.ZR载入(当前值)
	// 	return
	// default:
	// 	//返回_错误 = errors.New("错误:被取值的类型不是[]any")
	// 	return
	// }
}
func (类 *J键值表) QZ取字节集(路径或索引 any, 索引 ...any) (返回_值 []byte) {
	值, 返回_错误 := 类.Q取值(路径或索引, 索引...)
	if 返回_错误 != nil {
		return
	}
	switch 当前值 := 值.(type) {
	case []byte:
		返回_值 = 当前值
		return
	default:
		返回_值 = 全_类型.D到字节集(当前值)
		return
	}
}

func (类 *J键值表) QS取时间日期(路径或索引 any, 索引 ...any) (返回_值 time.Time) {
	值, 返回_错误 := 类.Q取值(路径或索引, 索引...)
	if 返回_错误 != nil {
		return
	}
	返回_值 = 全_类型.D到时间(值)
	return
}
func (类 *J键值表) QS取数量() int {
	类.初始化()
	if 类.读写许可 != nil {
		类.读写许可.RLock()
		defer 类.读写许可.RUnlock()
	}
	return len(类.原始数据)
}

// @ 1为升序 2为降序 空 或者 其它为不排序
func (类 *J键值表) QJ取键组(排序方式 ...int) []string {
	类.初始化()
	if 类.读写许可 != nil {
		类.读写许可.RLock()
		defer 类.读写许可.RUnlock()
	}
	jc := 0
	键组 := make([]string, len(类.原始数据))
	for k := range 类.原始数据 {
		键组[jc] = k
		jc++
	}
	if len(排序方式) == 0 {
		return 键组
	} else if 排序方式[0] == 1 {
		sort.Strings(键组)
	} else if 排序方式[0] == 2 {
		sort.Sort(sort.Reverse(sort.StringSlice(键组)))
	}
	return 键组
}

// 路径  用 . 分割  自动去除 前后包裹的 []  如 路径1.路径2.[0].路径4 | 路径1.路径2.0.路径4|路径1.[路径2].0.路径4"
// 索引 如果 后面索引不为空 则走 路径+索引 混合
func (类 *J键值表) Z置值(添加值 any, 路径或索引 any, 索引 ...any) (返回_错误 error) {
	路径组, err := 值列路径(路径或索引, 索引...)
	if err != nil {
		返回_错误 = err
		return
	}
	if 新值, ok := 添加值.(J键值表); ok {
		添加值 = 新值.D到map()
	} else if 新值, ok := 添加值.(L列表); ok {
		添加值 = 新值.D到切片()
	}

	类.初始化()
	if 类.读写许可 != nil {
		类.读写许可.Lock()
		defer 类.读写许可.Unlock()
	}

	返回_错误 = 键值列表_置值(类.原始数据, 路径组, 添加值)
	return
}

// 路径  用 . 分割  自动去除 前后包裹的 []  如 路径1.路径2.[0].路径4 | 路径1.路径2.0.路径4|路径1.[路径2].0.路径4"
// 索引 如果 后面索引不为空 则走 路径+索引 混合
func (类 *J键值表) ZZ置子切片_添加(添加值 any, 路径或索引 any, 索引 ...any) (返回_错误 error) {
	路径组, err := 值列路径(路径或索引, 索引...)
	if err != nil {
		返回_错误 = err
		return
	}
	if 新值, ok := 添加值.(J键值表); ok {
		添加值 = 新值.D到map()
	} else if 新值, ok := 添加值.(L列表); ok {
		添加值 = 新值.D到切片()
	}

	类.初始化()
	if 类.读写许可 != nil {
		类.读写许可.Lock()
		defer 类.读写许可.Unlock()
	}
	返回_错误 = 键值列表_子切片添加值(类.原始数据, 路径组, 添加值)
	return
}
func (类 *J键值表) L连续赋值(键值 ...any) (返回_错误 error) {
	类.初始化()
	if len(键值)%2 != 0 {
		返回_错误 = errors.New("错误:键值必须为一键 一值 的 双数")
	}
	var 键 string
	for i, v := range 键值 {
		if (i+1)%2 != 0 {
			switch 当前值 := v.(type) {
			case string:
				键 = 当前值
			default:
				返回_错误 = errors.New("错误:键值必须为 string")
				return
			}
		} else {
			返回_错误 = 类.Z置值(v, 键)
			if 返回_错误 != nil {
				return
			}
		}
	}
	return
}
func (类 *J键值表) C创建(键值 ...any) (返回_错误 error) {
	类.初始化()
	if 类.读写许可 != nil {
		类.读写许可.Lock()
		类.原始数据 = make(map[string]any)
		类.读写许可.Unlock()
	} else {
		类.原始数据 = make(map[string]any)
	}
	if len(键值)%2 != 0 {
		返回_错误 = errors.New("错误:键值必须为一键 一值 的 双数")
		return
	}
	var 键 string
	for i, v := range 键值 {
		if (i+1)%2 != 0 {
			switch 当前值 := v.(type) {
			case string:
				键 = 当前值
			default:
				返回_错误 = errors.New("错误:键值必须为 string")
				return
			}
		} else {
			返回_错误 = 类.Z置值(v, 键)
			if 返回_错误 != nil {
				return
			}
		}
	}

	return
}

// 路径  用 . 分割  自动去除 前后包裹的 []  如 路径1.路径2.[0].路径4 | 路径1.路径2.0.路径4|路径1.[路径2].0.路径4"
// 索引 如果 后面索引不为空 则走 路径+索引 混合
func (类 *J键值表) ZW置文本(添加值 string, 路径或索引 any, 索引 ...any) (返回_错误 error) {
	返回_错误 = 类.Z置值(添加值, 路径或索引, 索引...)
	return
}

// 路径  用 . 分割  自动去除 前后包裹的 []  如 路径1.路径2.[0].路径4 | 路径1.路径2.0.路径4|路径1.[路径2].0.路径4"
// 索引 如果 后面索引不为空 则走 路径+索引 混合
func (类 *J键值表) ZZ置整数(添加值 int, 路径或索引 any, 索引 ...any) (返回_错误 error) {
	返回_错误 = 类.Z置值(添加值, 路径或索引, 索引...)
	return
}

// 路径  用 . 分割  自动去除 前后包裹的 []  如 路径1.路径2.[0].路径4 | 路径1.路径2.0.路径4|路径1.[路径2].0.路径4"
// 索引 如果 后面索引不为空 则走 路径+索引 混合
func (类 *J键值表) ZX置小数(添加值 float64, 路径或索引 any, 索引 ...any) (返回_错误 error) {
	返回_错误 = 类.Z置值(添加值, 路径或索引, 索引...)
	return
}

// 路径  用 . 分割  自动去除 前后包裹的 []  如 路径1.路径2.[0].路径4 | 路径1.路径2.0.路径4|路径1.[路径2].0.路径4"
// 索引 如果 后面索引不为空 则走 路径+索引 混合
func (类 *J键值表) ZL置逻辑(添加值 bool, 路径或索引 any, 索引 ...any) (返回_错误 error) {
	返回_错误 = 类.Z置值(添加值, 路径或索引, 索引...)
	return
}

// 路径  用 . 分割  自动去除 前后包裹的 []  如 路径1.路径2.[0].路径4 | 路径1.路径2.0.路径4|路径1.[路径2].0.路径4"
// 索引 如果 后面索引不为空 则走 路径+索引 混合
func (类 *J键值表) ZZ置字节集(添加值 []byte, 路径或索引 any, 索引 ...any) (返回_错误 error) {
	返回_错误 = 类.Z置值(添加值, 路径或索引, 索引...)
	return
}

// 路径  用 . 分割  自动去除 前后包裹的 []  如 路径1.路径2.[0].路径4 | 路径1.路径2.0.路径4|路径1.[路径2].0.路径4"
// 索引 如果 后面索引不为空 则走 路径+索引 混合
func (类 *J键值表) ZS置时间日期(添加值 time.Time, 路径或索引 any, 索引 ...any) (返回_错误 error) {
	返回_错误 = 类.Z置值(添加值, 路径或索引, 索引...)
	return
}

// 路径  用 . 分割  自动去除 前后包裹的 []  如 路径1.路径2.[0].路径4 | 路径1.路径2.0.路径4|路径1.[路径2].0.路径4"
// 索引 如果 后面索引不为空 则走 路径+索引 混合
func (类 *J键值表) ZM置map(添加值 map[string]any, 路径或索引 any, 索引 ...any) (返回_错误 error) {
	返回_错误 = 类.Z置值(添加值, 路径或索引, 索引...)
	return
}
func (类 *J键值表) ZJ置键值表(添加值 J键值表, 路径或索引 any, 索引 ...any) (返回_错误 error) {
	返回_错误 = 类.Z置值(添加值, 路径或索引, 索引...)
	return
}

// 路径  用 . 分割  自动去除 前后包裹的 []  如 路径1.路径2.[0].路径4 | 路径1.路径2.0.路径4|路径1.[路径2].0.路径4"
// 索引 如果 后面索引不为空 则走 路径+索引 混合
func (类 *J键值表) ZQ置切片(添加值 []any, 路径或索引 any, 索引 ...any) (返回_错误 error) {
	返回_错误 = 类.Z置值(添加值, 路径或索引, 索引...)
	return
}

func (类 *J键值表) ZL置列表(添加值 L列表, 路径或索引 any, 索引 ...any) (返回_错误 error) {
	返回_错误 = 类.Z置值(添加值, 路径或索引, 索引...)
	return
}

// 路径  用 . 分割  自动去除 前后包裹的 []  如 路径1.路径2.[0].路径4 | 路径1.路径2.0.路径4|路径1.[路径2].0.路径4"
// 索引 如果 后面索引不为空 则走 路径+索引 混合
// 自动会把 []map[string]any 转换成 []any
func (类 *J键值表) ZM置map_组(添加值 []map[string]any, 路径或索引 any, 索引 ...any) (返回_错误 error) {
	返回_错误 = 类.Z置值(添加值, 路径或索引, 索引...)
	return
}

func (类 *J键值表) S删值(路径或索引 any, 索引 ...any) (返回_错误 error) {
	路径组, err := 值列路径(路径或索引, 索引...)
	if err != nil {
		返回_错误 = err
		return
	}
	类.初始化()
	if 类.读写许可 != nil {
		类.读写许可.Lock()
		defer 类.读写许可.Unlock()
	}

	返回值, 返回_错误 := 键值列表_删除值(类.原始数据, 路径组)
	if 值, ok := 返回值.(map[string]any); ok && 返回_错误 == nil {
		类.原始数据 = 值
	}
	return
}
func (类 *J键值表) ZR载入_重文件(文件路径 string) (返回_错误 error) {
	var data []byte
	data, 返回_错误 = 全_文件.D读入_文件(文件路径)
	if 返回_错误 != nil {
		return
	}
	类.初始化()
	if 类.读写许可 != nil {
		类.读写许可.Lock()
		defer 类.读写许可.Unlock()
	}
	返回_错误 = json.Unmarshal(data, &类.原始数据)
	if 返回_错误 != nil {
		return
	}
	return
}

func (类 *J键值表) B保存_到文件(文件路径 string) (返回_错误 error) {
	类.初始化()
	if 类.读写许可 != nil {
		类.读写许可.RLock()
		defer 类.读写许可.RUnlock()
	}
	新值, _ := 键值列表_深拷贝(类.原始数据)
	转换数据 := 键值列表_JSON之前处理(新值)
	JSON, err := json.Marshal(转换数据)
	if err != nil {
		返回_错误 = err
		return
	}
	返回_错误 = 全_文件.X写到_文件(文件路径, []byte(JSON))
	return
}

// 只支 判断持首层键
func (类 *J键值表) P判断键_是否存在(键名称 string) (返回_值 bool) {
	类.初始化()
	if 类.读写许可 != nil {
		类.读写许可.RLock()
		defer 类.读写许可.RUnlock()
	}
	_, 返回_值 = 类.原始数据[键名称]
	return
}

// @ 1为升序 2为降序 空 或者 其它为不排序
func (类 *J键值表) D到表单文本(排序方式 ...int) (返回_值 string) {
	排序 := 0
	if len(排序方式) > 0 {
		排序 = 排序方式[0]
	}
	键数组 := 类.QJ取键组(排序)
	var 列表 L列表
	for _, v := range 键数组 {
		提交值 := 类.QW取文本(v)
		列表.T添加值(v + "=" + 提交值)
	}
	返回_值 = 列表.L连接到文本("&")
	return
}

// 把其它键值表的值合并过来  相同的会被替换, 没有的会添加进来
func (类 *J键值表) H合并表(参数键值表 J键值表) {
	类.初始化()
	if 类.读写许可 != nil {
		类.读写许可.Lock()
		defer 类.读写许可.Unlock()
	}
	表数据 := 参数键值表.D到map()
	for 键, 值 := range 表数据 {
		类.原始数据[键] = 值
	}
}

// 把其它键值表的值合并成一个 新的返回表  相同的会被替换, 没有的会添加进来(不影响原表 )
func (类 *J键值表) H合并表_成新表(参数键值表 J键值表) (返回表 J键值表, 返回错误 error) {
	if &返回表.原始数据 == &类.原始数据 || &返回表.原始数据 == &参数键值表.原始数据 {
		返回错误 = errors.New("新表 不能是原有表")
		return

	}

	返回表.Q清空()
	类.初始化()
	if 类.读写许可 != nil {
		类.读写许可.Lock()
		defer 类.读写许可.Unlock()
	}
	新值, _ := 键值列表_深拷贝(类.原始数据)
	返回表.ZR载入(新值)
	表数据 := 参数键值表.D到map()
	for 键, 值 := range 表数据 {
		返回表.原始数据[键] = 值
	}
	return
}

//类似 a=b,c=666 这样的文本 用 , 和 = 分割出表
func (类 *J键值表) C重文本分割(文本 string, 表割符 string, 键割符 string) (返回_错误 error) {
	类.初始化()
	if 类.读写许可 != nil {
		类.读写许可.Lock()
		defer 类.读写许可.Unlock()
	}
	类.原始数据 = make(map[string]any)
	分割组 := 全_文本.F分割文本(文本, 表割符)
	for _, v := range 分割组 {
		键值组:=全_文本.F分割文本(v, 键割符)
		if len(键值组)!=2{
			返回_错误=errors.New("键值不成对")
			return
		}
		类.原始数据[键值组[0]]=键值组[1]


	}
	return

}
